﻿using System;
using System.Runtime.Serialization;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace Dynamic.Data.Model.Query
{
    [DataContract]
    [XmlType(Namespace="DynamicMatrix"), XmlInclude(typeof(LinkEntity)), XmlInclude(typeof(OrderExpression))]
    public sealed class QueryExpression : QueryBase
    {
        private FilterExpression _criteria;
        private bool _distinct = false;
        private List<LinkEntity> _linkEntities;
        private List<OrderExpression> _orders;
        private PagingInfo _pageInfo;

        public QueryExpression()
        {
            this._pageInfo = new PagingInfo();
            this._linkEntities = new List<LinkEntity>();
            this._criteria = new FilterExpression();
            this._orders = new List<OrderExpression>();
        }

        public override void Accept(IQueryVisitor visitor)
        {
            visitor.Visit(this);
        }

        public LinkEntity AddLink(string linkToEntityName, string linkFromAttributeName, string linkToAttributeName)
        {
            return this.InternalAddLink(linkToEntityName, linkFromAttributeName, linkToAttributeName, JoinOperator.Inner);
        }

        public LinkEntity AddLink(string linkToEntityName, string linkFromAttributeName, string linkToAttributeName, JoinOperator joinOperator)
        {
            return this.InternalAddLink(linkToEntityName, linkFromAttributeName, linkToAttributeName, joinOperator);
        }

        public void AddOrder(string attributeName, OrderType orderType)
        {
            OrderExpression expression = new OrderExpression {
                AttributeName = attributeName,
                OrderType = orderType
            };
            this._orders.Add(expression);
        }

        private LinkEntity InternalAddLink(string linkToEntityName, string linkFromAttributeName, string linkToAttributeName, JoinOperator joinOperator)
        {
            LinkEntity entity = new LinkEntity(base.EntityName, linkToEntityName, linkFromAttributeName, linkToAttributeName, joinOperator);
            this._linkEntities.Add(entity);
            return entity;
        }

        [DataMember]
        public FilterExpression Criteria
        {
            get
            {
                return this._criteria;
            }
            set
            {
                this._criteria = value;
            }
        }

        [DataMember]
        public bool Distinct
        {
            get
            {
                return this._distinct;
            }
            set
            {
                this._distinct = value;
            }
        }

        [DataMember]
        [XmlArrayItem(ElementName="LinkEntity", IsNullable=false, Type=typeof(LinkEntity)), XmlArray]
        public List<LinkEntity> LinkEntities
        {
            get
            {
                return this._linkEntities;
            }
            set
            {
                this._linkEntities = value;
            }
        }

        [DataMember]
        [XmlArray, XmlArrayItem(ElementName="Order", IsNullable=false, Type=typeof(OrderExpression))]
        public List<OrderExpression> Orders
        {
            get
            {
                return this._orders;
            }
            set
            {
                this._orders = value;
            }
        }

        [DataMember]
        public PagingInfo PageInfo
        {
            get
            {
                return this._pageInfo;
            }
            set
            {
                this._pageInfo = value;
            }
        }
    }
}

